﻿using System;
using System.Collections.Generic;
using HK.Core.Common.Data;
using HK.Core.Common.Protocol;
using HK.Core.Common.Protocol.Data;
using HK.Editor.GUIEx.Protocol.TreeView.Data;
using UnityEngine;

namespace HK.Editor.GUIEx.TreeView.Data
{
    /// <summary>
    /// 树枝空引用异常
    /// </summary>
    public class TreeBranchNullReferenceException : NullReferenceException
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="iMessage">Message</param>
        public TreeBranchNullReferenceException(string iMessage) : base(iMessage) {}
    }

    /// <summary>
    /// 树枝参数异常
    /// </summary>
    public class TreeBranchArgumentException : ArgumentException
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="iMessage">Message</param>
        public TreeBranchArgumentException(string iMessage) : base(iMessage) {}
        
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="iParam">参数</param>
        /// <param name="iMessage">Message</param>
        public TreeBranchArgumentException(string iParam, string iMessage) : base(iParam, iMessage) {}
    }

    public static class TreeBranchUtility
    {
        /// <summary>
        /// 当前树枝转换为列表
        /// </summary>
        /// <param name="iBranch">树枝节点</param>
        /// <param name="oBranches">树枝列表</param>
        /// <typeparam name="TBranch">树枝类型</typeparam>
        /// <exception cref="TreeBranchNullReferenceException">树枝空引用异常</exception>
        public static void TreeBranchToList<TBranch>(TBranch iBranch, IList<TBranch> oBranches) where TBranch : ITreeBranch
        {
            if (null == oBranches)
            {
                throw new TreeBranchNullReferenceException("The branches 'IList<T> oBranches' list is null");
            }
            oBranches.Clear();

            var stack = new Stack<TBranch>();
            
            // 压入根节点
            stack.Push(iBranch);

            // 循环遍历
            while (stack.Count > 0)
            {
                var current = stack.Pop();
                oBranches.Add(current);

                // 倒序
                if (null != current.Children && 0 < current.ChildCount)
                {
                    var count = current.ChildCount;
                    for (var idx = count - 1; idx >= 0; --idx)
                    {
                        stack.Push((TBranch)current.Children[idx]);
                    }
                }
            }
        }
        
        /// <summary>
        /// 列表转换成树枝
        /// </summary>
        /// <param name="iBranches">树枝列表</param>
        /// <typeparam name="TBranch">树枝类型</typeparam>
        /// <returns>树枝</returns>
        public static TBranch ListToTreeBranch<TBranch>(IList<TBranch> iBranches) where TBranch : JsonData, ITreeBranch
        {
            // 验证树枝列表有效性
            ValidateDepthValues (iBranches);

            // 清空列表所有状态
            foreach (var branch in iBranches)
            {
                if(null == branch) continue;
                
                branch.Parent = null;
                branch.Children = null;
            }

            var count = iBranches.Count;
            // Set child and parent references using depth info
            for (var parentIndex = 0; parentIndex < count; parentIndex++)
            {
                var parent = iBranches[parentIndex];
                if(null == parent) continue;
                
                var parentDepth = parent.Depth;
                var childCount = 0;

                // 校验当前节点是否为以后节点的父节点
                for (var idx = parentIndex + 1; idx < iBranches.Count; idx++)
                {
                    if (iBranches[idx].Depth == parentDepth + 1) childCount++;
                    if (iBranches[idx].Depth <= parentDepth) break;
                }

                // 若当前节点为之后若干节点的父节点,则设置之后节点的父节点，以及设置当前节点的子节点列表
                List<ITreeBranch> childList = null;
                if (childCount != 0)
                {
                    childList = new List<ITreeBranch>(childCount); // Allocate once
                    childCount = 0;
                    for (var idx = parentIndex + 1; idx < iBranches.Count; ++idx)
                    {
                        if (iBranches[idx].Depth == parentDepth + 1)
                        {
                            iBranches[idx].Parent = parent;
                            childList.Add(iBranches[idx]);
                            childCount++;
                        }

                        if (iBranches[idx].Depth <= parentDepth)
                            break;
                    }
                }

                parent.Children = childList;
            }

            return iBranches[0];
        }
        
        /// <summary>
        /// 校验树枝列表的深度信息
        /// </summary>
        /// <param name="iBranches">分支列表</param>
        /// <typeparam name="TBranch">树枝类型</typeparam>
        /// <exception cref="TreeBranchArgumentException"></exception>
        public static void ValidateDepthValues<TBranch>(IList<TBranch> iBranches) where TBranch : ITreeBranch
        {
            if (null == iBranches || 0 >= iBranches.Count)
            {
                throw new TreeBranchArgumentException("iList", "列表为null，或者数量为0");
            }

            // 校验第一个节点是否为根节点
            var firstBranch = iBranches[0];
            if (!firstBranch.IsRoot)
            {
                throw new TreeBranchArgumentException("iList", "列表首节点不是根节点. Depth is: " + firstBranch.Depth);
            }

            var count = iBranches.Count;
            // 遍历列表，进行深度校验
            for (var idx = 0; idx < count - 1; ++idx)
            {
                var curBranch = iBranches[idx];
                if (null == curBranch || !curBranch.Valid)
                {
                    throw new TreeBranchArgumentException("iList", $"存在无效节点!({idx}/{count})");
                }
                if(curBranch.IsRoot) continue;

                var nextBranch = iBranches[idx + 1];
                if (null == nextBranch || !nextBranch.Valid)
                {
                    throw new TreeBranchArgumentException("iList", $"存在无效节点!({idx+1}/{count})");
                }
                
                var curDepth = curBranch.Depth;
                var nextDepth = nextBranch.Depth;
                if (nextDepth > curDepth && nextDepth - curDepth > 1)
                {
                    throw new TreeBranchArgumentException(
                        $"上下节点深度超过1！(CurBranch:Index {idx} depth {curDepth}; NextBranch:Index {idx + 1} depth {nextDepth}");
                }
            }

            // 非根节点深度校验
            for (var idx = 1; idx < count; ++idx)
            {
                var curBranch = iBranches[idx];
                if (null == curBranch || !curBranch.Valid)
                {
                    throw new TreeBranchArgumentException("iList", $"存在无效节点!({idx}/{count})");
                }

                if (curBranch.IsRoot)
                {
                    throw new TreeBranchArgumentException(
                        $"超过两个根节点！(CurBranch:Index {idx} depth {curBranch.Depth};");
                }
            }

            // 校验第一个节点深度值
            if (1 < count && 0 != iBranches[1].Depth)
            {
                throw new TreeBranchArgumentException(
                    $"第一个节点深度值必须为0！(Depth {iBranches[1].Depth};");
            }
        }
        
        /// <summary>
        /// 更新指定根节点的深度关系
        /// </summary>
        /// <param name="iRoot">根节点</param>
        /// <exception cref="TreeBranchArgumentException">树枝参数异常</exception>
        public static void UpdateDepthValues(ITreeBranch iRoot)
        {
            if (null == iRoot)
            {
                throw new TreeBranchArgumentException("iRoot", "The root is null");
            }
            
            // 没有子节点
            if (!iRoot.HasChildren) return;

            var stack = new Stack<ITreeBranch>();
            stack.Push(iRoot);
            
            while (stack.Count > 0)
            {
                var current = stack.Pop();
                if (!current.ValidChildren || 0 >= current.ChildCount) continue;
                
                // 遍历子节点
                foreach (var child in current.Children)
                {
                    child.Depth = current.Depth + 1;
                    stack.Push(child);
                }
            }
        }
        
        /// <summary>
        /// 校验列表是否包含子节点
        /// </summary>
        /// <param name="iChild">子节点</param>
        /// <param name="iBranches">分支列表</param>
        /// <typeparam name="TBranch">树枝类型</typeparam>
        /// <returns>true:包含; false:不包含;</returns>
        private static bool IsChildOf<TBranch>(TBranch iChild, IList<TBranch> iBranches) where TBranch : ITreeBranch
        {
            var curChild = iChild;
            var exist = false;
            while (null != curChild)
            {
                curChild = (TBranch)curChild.Parent;
                if (iBranches.Contains(curChild))
                {
                    exist = true;
                    break;
                }
            }
            return exist;
        }
        
        public static IList<TBranch> FindCommonAncestorsWithinList<TBranch>(IList<TBranch> iBranches) where TBranch : ITreeBranch
        {
            if (1 == iBranches.Count)
            {
                return new List<TBranch>(iBranches);
            }

            var result = new List<TBranch>(iBranches);
            result.RemoveAll(branch => IsChildOf(branch, iBranches));
            return result;
        }
    }
    
    /// <summary>
    /// 树枝
    /// </summary>
    /// <typeparam name="TBranch">树枝类型</typeparam>
    [Serializable]
    public abstract class TreeBranch<TBranch> : JsonData<TBranch>, ITreeBranch
        where TBranch : JsonData, ITreeBranch
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        protected TreeBranch () { }
        
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="iId">Id</param>
        /// <param name="iName">Name</param>
        /// <param name="iDepth">深度</param>
        protected TreeBranch (int iId, string iName, int iDepth)
        {
            Id = iId;
            Name = iName;
            Depth = iDepth;
        }
        
        [SerializeField]
        private int id = -1;
        /// <summary>
        /// Id
        /// </summary>
        public int Id
        {
            get => id;
            set => id = value;
        }

        [SerializeField]
        private string name = null;
        /// <summary>
        /// Name
        /// </summary>
        public virtual string Name 
        {
            get => name;
            set => name = value;
        }
        
        [SerializeField]
        private int depth = -1;
        /// <summary>
        /// 深度
        /// </summary>
        public int Depth 
        {
            get => depth;
            set => depth = value;
        }

        /// <summary>
        /// 根节点Id
        /// </summary>
        private static readonly int RootDepth = -1;

        /// <summary>
        /// 根节点标志位
        /// </summary>
        public bool IsRoot => RootDepth >= depth;

        /// <summary>
        /// 父节点
        /// </summary>
        public ITreeBranch Parent { get; set; } = null;
        
        /// <summary>
        /// 子节点列表
        /// </summary>
        public List<ITreeBranch> Children { get; set; } = null;

        /// <summary>
        /// 子节点数量
        /// </summary>
        public int ChildCount => ValidChildren ? Children.Count : 0;

        /// <summary>
        /// 子节点列表有效标志位
        /// </summary>
        public bool ValidChildren => null != Children;

        /// <summary>
        /// 是否拥有子节点标志位
        /// </summary>
        public bool HasChildren => 0 < ChildCount;
        
        /// <summary>
        /// 有效标志位
        /// </summary>
        public override bool Valid => !string.IsNullOrEmpty(name);

        /// <summary>
        /// 应用数据
        /// </summary>
        /// <param name="iData">数据</param>
        /// <param name="iImport">导入标志位(true:从相应的*.json文件导入; false:反之;)</param>
        /// <returns>true:有变更; false:无变更;</returns>
        public override bool ApplyData(IJsonData iData, bool iImport = false)
        {
            if (null == iData || !iData.Valid) return false;

            var dirty = base.ApplyData(iData, iImport);
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            if (iData is ITreeBranch branch)
            {
                id = UpdateValue(id, branch.Id, iImport);
                name = UpdateValue(name, branch.Name, iImport);
                depth = UpdateValue(depth, branch.Depth, iImport);
            }

            return Dirty;
        }

        /// <summary>
        /// 清空
        /// </summary>
        public override void Clear()
        {
            base.Clear();
            
            id = -1;
            name = null;
            depth = -1;

            Parent = null;
            Children?.Clear();
            Children = null;
        }
    }
}
